package com.myapp.web.filter;

import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;

public class AuthFilter implements Filter
{
    private final static Log logger = LogFactory.getLog(AuthFilter.class);
    
    public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";
    
    public static final String REDIRECT_PATH = "/global/404.jsp";
    
    public static final String LOGIN_SESSION_KEY = "login";
    
	private FilterConfig filterConfig;
	
	public static final String AUTH_PATH_PARAM_NAME   = "path";
	
	public static final String AUTH_EXCEPT_PARAM_NAME = "except_path";
	
	protected String[] authFilterPath;
	
	protected String[] exceptFilterPath;
	
    @Override
    public void destroy() {    	
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
    		throws IOException, ServletException {
    	if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
			throw new ServletException("OncePerRequestFilter just supports HTTP requests");
		}
    	HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;

		String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
		if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) {
			// Proceed without invoking this filter...
			filterChain.doFilter(request, response);
		}
		else {
			// Do invoke this filter...
			request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
			try {
				doFilterInternal(httpRequest, httpResponse, filterChain);
			}
			finally {
				// Remove the "already filtered" request attribute for this request.
				request.removeAttribute(alreadyFilteredAttributeName);
			}
		}
    	
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    	Assert.notNull(filterConfig, "FilterConfig must not be null");
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing filter '" + filterConfig.getFilterName() + "'");
		}

		this.filterConfig = filterConfig;

		@SuppressWarnings("rawtypes")
		Enumeration en = filterConfig.getInitParameterNames();
		while (en.hasMoreElements()) {
			String property = (String) en.nextElement();
			String value = (String)filterConfig.getInitParameter(property);
			if(AUTH_PATH_PARAM_NAME.equalsIgnoreCase(property)){
				if(!StringUtils.isBlank(value)){
					authFilterPath   = value.split(",");
				}
			}else if(AUTH_EXCEPT_PARAM_NAME.equalsIgnoreCase(property)){
				if(!StringUtils.isBlank(value)){
					exceptFilterPath = value.split(",");
				}
			}
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully");
		}    	
    }
    
    protected final String getFilterName() {
		return (this.filterConfig != null ? this.filterConfig.getFilterName() : this.getClass().getName());
	}
    
    protected String getAlreadyFilteredAttributeName() {
		String name = getFilterName();
		if (name == null) {
			name = getClass().getName();
		}
		return name + ALREADY_FILTERED_SUFFIX;
	}
    
    protected void doFilterInternal(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException
    {
        try{
        	if(request.getSession().getAttribute(LOGIN_SESSION_KEY) == null)
        	{
            	response.sendRedirect(REDIRECT_PATH);
        	}else{
                chain.doFilter(request, response);
        	}
        }catch (Exception e){
        	logger.error("doFilterInternal error", e);
        }
    }

    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
    	String path = request.getRequestURI();
    	if(authFilterPath == null || authFilterPath.length == 0){
    		return true;
    	}
    	
    	for (int i = 0; i < authFilterPath.length; i++){
    		if (path.startsWith(authFilterPath[i])){
    			return false;
    		}
    	}
    	return true;
	}       
}
